<?php

/**
 * class provides functions for latex-text-conversion
 *
 * @author voellenk
 */

class sanitizer {
  public $rawstring;
  public $sanitized="";
  public $expectedpos=array(
    "Hammer\_D", "InvertedHammer\_D", "BullDoji\_D", "DragonflyDoji\_D",
    "WhiteMarubozu\_D", "WhiteMarubozu\_U", "GapUp\_D", "GapUp\_U", "UpsideTasukiGap\_U",
    "BullEngulfing\_D", "PiercingPattern\_D", "AboveTheStomache\_D", "BullHarami\_D",
    "MorningStar\_D", "ThreeWhiteSoldiers\_D"
  );
  public $expectedneg=array(
    "HangingMan\_U", "ShootingStar\_U", "BearDoji\_U", "GravestoneDoji\_U",
    "BlackMarubozu\_U", "GapDown\_U", "BlackMarubozu\_D", "GapDown\_D", "DownsideTasukiGap\_D",
    "BearEngulfing\_U", "DarkCloudCover\_U", "BelowTheStomache\_U", "BearHarami\_U",
    "EveningStar\_U", "ThreeBlackCrows\_U"
  );
  public $expectednodir=array(
    "Random\_U", "Random\_D"
  );
  public $straightpattern=array(
    "Hammer\_D\_long",
    "HangingMan\_U\_short",
    "InvertedHammer\_D\_long",
    "ShootingStar\_U\_short",
    "WhiteMarubozu\_D\_long",
    "WhiteMarubozu\_U\_long",
    "BlackMarubozu\_U\_short",
    "BlackMarubozu\_D\_short",
    "BullDoji\_D\_long",
    "BearDoji\_U\_short",
    "DragonflyDoji\_D\_long",
    "GravestoneDoji\_U\_short",
    "GapUp\_D\_long",
    "GapUp\_U\_long",
    "GapDown\_U\_short",
    "GapDown\_D\_short",
    "UpsideTasukiGap\_U\_long",
    "DownsideTasukiGap\_D\_short",
    "BullEngulfing\_D\_long",
    "BearEngulfing\_U\_short",
    "DarkCloudCover\_U\_short",
    "PiercingPattern\_D\_long",
    "AboveTheStomache\_D\_long",
    "BelowTheStomache\_U\_short",
    "BullHarami\_D\_long",
    "BearHarami\_U\_short",
    "MorningStar\_D\_long",
    "EveningStar\_U\_short",
    "ThreeWhiteSoldiers\_D\_long",
    "ThreeBlackCrows\_U\_short"
  );
  public $groupidentifier1 = array(
    "FOREX_MAJORS_OOS",
    "FOREX_MAJORS",
    "INDEX_MAJORS_OOS", 
    "INDEX_MAJORS",
    "DJI_STOCKS_OOS",    
    "DJI_STOCKS",
    "SMALL_CAPS_OOS",
    "SMALL_CAPS",
    "METALS_OOS",
    "METALS",
    "AGRICULTURE_OOS",
    "AGRICULTURE",
    "mean",
    "ratio"
  );
  public $groupidentifier2 = array(
    "Währungspaare (Out of Sample)",      
    "Währungspaare",
    "Indexe (Out of Sample)",
    "Indexe",
    "Aktien des Dow Jones (Out of Sample)",
    "Aktien des Dow Jones",
    "Small Caps (Out of Sample)",
    "Small Caps",
    "Edelmetalle (Out of Sample)",
    "Edelmetalle",
    "Agrarrohstoffe (Out of Sample)",
    "Agrarrohstoffe",
    "Stoplimits optimiert nach höchster Durchschnittsrendite",
    "Stoplimits optimiert nach bestem Rendite/Risikoverhältnis"
  );
  
  public function sanitize_tableRetMeanSd($rawstring) {
    $this->rawstring=$rawstring;
    // set font size
    $san=$this->fontsize($this->rawstring, "\scriptsize");
    // replace obs with #obs
    $san=str_replace("Obs", "\#Obs", $san);
    // explode at first occurance of \hline
    $expsan = explode("\hline", $san, 2);
    // insert title row
    $title ="\hline
    & \multicolumn{2}{c|}{t+2} 
    & \multicolumn{2}{c|}{t+5}
    & \multicolumn{2}{c|}{t+10}
    & \multicolumn{2}{c|}{t+20}
    & \multicolumn{1}{c|}{} \\\\";
    $san=implode(array($expsan[0], $title, $expsan[1]));
    
    // arrange rows in fixed order
    $expsan = explode("\hline", $san);
    $expsan[2] = $this->arrangeRows($expsan[2], true);
    
    // eliminate "pattern"
    $expsan[1] = str_replace("pattern", "", $expsan[1]);
    
    // reassemble everything
    $san = implode("\hline", $expsan);
    
    $this->sanitized=$san;
    return true;
  }
  
  public function sanitize_tableAllGroupsSummary($rawstring) {
    $this->rawstring=$rawstring;
    $san=$this->fontsize($this->rawstring, "\scriptsize");
    // explode at first occurance of \hline
    $expsan = explode("\hline", $san, 2);
    $title ="\hline
    & \multicolumn{2}{c|}{Indexe}
    & \multicolumn{2}{c|}{Aktien DJI} 
    & \multicolumn{2}{c|}{Small Caps}
    & \multicolumn{2}{c|}{Edelmetalle} 
    & \multicolumn{2}{c|}{Agrarrohstoffe} 
    & \multicolumn{2}{c|}{Währungen}\\\\";
    $san=implode(array($expsan[0], $title, $expsan[1]));  
    
    // fix last line, therefore explode again
    $expsan = explode("\hline", $san);
    $clines = explode("\n", trim($expsan[2]));
    $clines[sizeof($clines)-1] = "\hline\n Gesamt ".str_replace("0.00", "", $clines[sizeof($clines)-1])."\n";
    $clines[0] = "\n".$clines[0];
    
    // reassemble everything
    $expsan[2] = implode("", $clines);
    $san = implode("\hline", $expsan);
    
    $this->sanitized=$san;
    return true;   
  }
  
  // sanitizes whole list of tables
  public function sanitize_tableAllTopStopLogicPatterns($rawstring) {
    $this->rawstring=trim($rawstring);
    $explodestring="\end{table}";
    //explode for end of table
    $expsan = explode($explodestring, $this->rawstring);
 
    for($i=0; $i<sizeof($expsan)-1; $i++) {
      // outsource this to own function
      $tablestring[$i] = $this->sanitize_thistable($expsan[$i]);
    }
    
    //re-implode all tables
    $this->sanitized=implode($explodestring."\n\n", $tablestring);
    return true;
  }
  
  // sanitizes whole list of tables
  public function sanitize_tableNextCandleGroupOverview($rawstring) {
    $this->rawstring=trim($rawstring);
    $explodestring="\end{table}";
    //explode for end of table
    $expsan = explode($explodestring, $this->rawstring);
 
    for($i=0; $i<sizeof($expsan)-1; $i++) {
      // outsource this to own function
      $tablestring[$i] = $this->sanitize_thisNextCandleGroupOverviewTable($expsan[$i]);
    }
    
    //re-implode all tables
    $this->sanitized=implode($explodestring."\n\n", $tablestring).$explodestring;
    return true;
  }
  
  // sanitizes whole list of tables  
  public function sanitize_tableAppliedStrategy($rawstring) {
    $this->rawstring=trim($rawstring);
    $explodestring="\end{table}";
    //explode for end of table
    $expsan = explode($explodestring, $this->rawstring);
 
    for($i=0; $i<sizeof($expsan)-1; $i++) {
      // outsource this to own function
      $tablestring[$i] = $this->sanitize_thisAppliedStrategyTable($expsan[$i]);
    }
    
    //re-implode all tables
    $this->sanitized=implode($explodestring."\n\n", $tablestring).$explodestring;
    return true;
  }
  
  public function sanitize_tableStockStatus($rawstring) {
    $this->rawstring=trim($rawstring);
    $explodestring="\end{table}";
    //explode for end of table
    $expsan = explode($explodestring, $this->rawstring);

    for($i=0; $i<sizeof($expsan)-1; $i++) {
      // outsource this to own function
      $tablestring[$i] = $this->sanitize_thisTableStockStatus($expsan[$i]);
    }
    
    //re-implode all tables
    $this->sanitized=implode($explodestring."\n\n", $tablestring).$explodestring;
    return true;    
  }
  
  private function sanitize_thisTableStockStatus($rawstring) {
    $explodestring="\hline";
    $san = $this->fontsize($rawstring, "\scriptsize");
    $expsan = explode($explodestring, $san);
    
    $expsan[1] = " & \multicolumn{4}{c|}{In-Sample} & \multicolumn{4}{c|}{Out-Of-Sample} & \\\\".$expsan[1];
    
    $rows = explode("\n", trim($expsan[2]));
    for($i=0; $i<sizeof($rows); $i++){
      $cells=explode("&", $rows[$i]);
      if (($cells[4] > 0 & $cells[8] < 0) | ($cells[4] < 0 & $cells[8] > 0)) {
        $rows[$i] = "\\rowcolor{LightRed}\n".$rows[$i];
      } 
    }
    $expsan[2]="\n".implode("\n", $rows)."\n";
    
    //re-implode all parts
    $san=implode($explodestring, $expsan);    
    return $san;    
  }
  
  private function sanitize_thisAppliedStrategyTable($rawstring) {
    $explodestring="\hline";
    $san = $this->fontsize($rawstring, "\scriptsize");
    $expsan = explode($explodestring, $san);
    
    $expsan[2] = $this->addhlineatlastline($expsan[2]);
    
    $expsan[3] = str_replace($this->groupidentifier1, 
                             $this->groupidentifier2, $expsan[3]);
    
    //re-implode all parts
    $san=implode($explodestring, $expsan);    
    return $san;
  }
  
  private function sanitize_thisNextCandleGroupOverviewTable($rawstring) {
    $explodestring="\hline";
    $san = $this->fontsize($rawstring, "\scriptsize");
    $expsan = explode($explodestring, $san);
    
    // replace titlerow
    $expsan[1] ="
    & \multicolumn{2}{c|}{Eröffnung}
    & \multicolumn{2}{c|}{Schluss} 
    & \multicolumn{2}{c|}{Kerzenfarbe} & \\\\
    & höher & tiefer & höher & tiefer & weiß & schwarz & \\\\
    & \$O_{t+1} > C_t\$ & \$O_{t+1} < C_t\$ & 
      \$C_{t+1} > C_t\$ & \$C_{t+1} < C_t\$ & 
      \$C_{t+1} > O_{t+1}\$ & \$C_{t+1} < O_{t+1}\$ & \#Obs\\\\ ";
    
    // bring datalines in order and eliminate rows with few observations
    $expsan[2] = $this->arrangeRows($expsan[2], false);
    $expsan[2] = $this->eliminateRowsWithVewObservations($expsan[2], 10);
    $expsan[2] = $this->markDivergingPairs($expsan[2], 6);
    
    $expsan[3] = str_replace($this->groupidentifier1, 
                             $this->groupidentifier2, $expsan[3]);
    
    //print_r($expsan);
    
    //re-implode all parts
    $san=implode($explodestring, $expsan);    
    return $san;
  }
  
  // sanitize one distinct table
  private function sanitize_thistable($rawstring) {
    $explodestring="\hline";
    $san = $this->fontsize($rawstring, "\scriptsize");
    $expsan = explode($explodestring, $san);
    // sanitize titlerow
    $expsan[1]=  str_replace(array("notrades", "SLPct", "SWPct", "PWin"), 
                             array("\#Trades", "\%SL","\%SW","\%Win"), $expsan[1]);
    // sanitize the ten datalines
    $datalines=explode("\n", trim($expsan[2]));
    for($i=0; $i<sizeof($datalines); $i++) {
      $cells=array();
      $cells = explode("&", $datalines[$i]);
      if (!in_array(trim($cells[0]), $this->straightpattern)) {
        $cells[0]="\\rowcolor{LightRed}\n".$cells[0];
      }
      if ($cells[2]==0) $cells[2]="-";
      if ($cells[3]==0) $cells[3]="-";      
      $cells[4]=round($cells[4], 1);
      $cells[5]=round($cells[5], 1);      
      if ($cells[4]==0) $cells[4]="0";   
      if ($cells[5]==0) $cells[5]="0";   
      $datalines[$i]= implode(" & ", $cells);
    }
    $expsan[3] = str_replace($this->groupidentifier1, 
                             $this->groupidentifier2, $expsan[3]);
    
    //re-implode all datalines
    $expsan[2]="\n".implode("\n", $datalines)."\n";
    //re-implode all parts
    $san=implode($explodestring, $expsan);
    return $san;
  }
  
  private function addhlineatlastline($rows) {
     $exprows=explode("\n", trim($rows));
     $exprows[sizeof($exprows)-2] .= "\n\hline";
     $slastline = explode("&", $exprows[sizeof($exprows)-1]);
     $slastline[0]="&lt;Sum&gt;";
     $lastline=array();
     $lastline[0]="&lt;Mean&gt;";
     $lastline[1]="";
     $lastline[2]="";
     $lastline[3]=$slastline[3];
     for ($i = 3; $i<sizeof($slastline); $i++) {
       $slastline[$i]="";
     }
     for ($i = 4; $i<sizeof($slastline); $i++) {
       $lastline[$i]="";
     }
     $exprows[sizeof($exprows)-1] = implode(" & ", $slastline)."\\\\\n";
     $exprows[sizeof($exprows)] = implode(" & ", $lastline)."\\\\\n";     
     return("\n".implode("\n", $exprows)."\n");
  }
  
  // filters key for arrangeRows function and add_color function
  private function filter_key($string) {
    $fullkey = trim($string);
    $keyarr = explode("\\", $fullkey);
    $keyonlytwo = array($keyarr[0], $keyarr[1]);
    $key=implode("\\", $keyonlytwo);  
    return($key);
  }
  
  private function arrangeRows($rows, $addcolor=false) {
    $sorted = array();
    $exprows=explode("\n", trim($rows));
    for ($i=0; $i<sizeof($exprows); $i++) {
      $cells = explode("&", $exprows[$i]);
      $key = $this->filter_key($cells[0]);
      $sorted[$key] = trim($exprows[$i]);
    }
    /*
    echo "<pre>\n";
    print_r ($exprows);
    print_r ($sorted);
    print_r ($sorted);    
    echo "</pre>\n";
    */
    // add color
    if ($addcolor == true) $sorted = $this->add_color($sorted);
    // arrange the array in wanted order
    $returnstring = implode ("\n", array(
        $sorted["Hammer\_D"],
        $sorted["HangingMan\_U"],
        $sorted["InvertedHammer\_D"],
        $sorted["ShootingStar\_U"],
        $sorted["BullDoji\_D"],
        $sorted["BearDoji\_U"],
        $sorted["DragonflyDoji\_D"],
        $sorted["GravestoneDoji\_U"],
        $sorted["WhiteMarubozu\_D"],
        $sorted["WhiteMarubozu\_U"],
        $sorted["BlackMarubozu\_U"],
        $sorted["BlackMarubozu\_D"],
        $sorted["GapUp\_D"],
        $sorted["GapUp\_U"],
        $sorted["GapDown\_U"],
        $sorted["GapDown\_D"],
        $sorted["UpsideTasukiGap\_U"],
        $sorted["DownsideTasukiGap\_D"],
        $sorted["BullEngulfing\_D"],
        $sorted["BearEngulfing\_U"],
        $sorted["PiercingPattern\_D"],
        $sorted["DarkCloudCover\_U"],
        $sorted["AboveTheStomache\_D"],
        $sorted["BelowTheStomache\_U"],        
        $sorted["BullHarami\_D"],
        $sorted["BearHarami\_U"],
        $sorted["MorningStar\_D"],
        $sorted["EveningStar\_U"],
        $sorted["ThreeWhiteSoldiers\_D"],
        $sorted["ThreeBlackCrows\_U"],
        $sorted["Random\_U"],
        $sorted["Random\_D"]       
        ));
    
    return ("\n".$returnstring."\n");
  }
  
  # also eliminates the Random Rows
  private function eliminateRowsWithVewObservations($rows, $limit) {
    $exprows=explode("\n", trim($rows));
    $retrows=array();
    for ($i=0; $i<sizeof($exprows); $i++) {
      $cells = explode("&", $exprows[$i]);
      if ($cells[sizeof($cells)-1] < $limit | substr_count($cells[0],"Random")>0) {
        $retrows[$i] = "";
      } else {
        $retrows[$i] = $exprows[$i];
      }
    }
    return("\n".implode("\n",$retrows));
  }
  
    private function markDivergingPairs_orig($rows, $limit) {
    $exprows=explode("\n", trim($rows));
    $retrows=array();
    for ($i=0; $i<sizeof($exprows); $i++) {
      $cells = explode("&", $exprows[$i]);
      if (sizeof($cells)>1) {
        if (abs($cells[1] - $cells[2]) > $limit) {
          if ($cells[1] < $cells[2]) {
            $cells[1] = $this->replace_add_color($cells[1], "red");
            $cells[2] = $this->replace_add_color($cells[2], "blue");
          } else {
            $cells[1] = $this->replace_add_color($cells[1], "blue");
            $cells[2] = $this->replace_add_color($cells[2], "red");          
          }
        }
        if (abs($cells[3] - $cells[4]) > $limit) {
          if ($cells[3] < $cells[4]) {
            $cells[3] = $this->replace_add_color($cells[3], "red");
            $cells[4] = $this->replace_add_color($cells[4], "blue");
          } else {
            $cells[3] = $this->replace_add_color($cells[3], "blue");
            $cells[4] = $this->replace_add_color($cells[4], "red");          
          }
        }
        if (abs($cells[5] - $cells[6]) > $limit) {
          if ($cells[5] < $cells[6]) {
            $cells[5] = $this->replace_add_color($cells[5], "red");
            $cells[6] = $this->replace_add_color($cells[6], "blue");
          } else {
            $cells[5] = $this->replace_add_color($cells[5], "blue");
            $cells[6] = $this->replace_add_color($cells[6], "red");          
          }
        }
      }
      $retrows[$i]= implode("&", $cells);
    }    
    return("\n".implode("\n",$retrows));
  }
  
  private function calcmidpoint($higher, $lower) {
    return abs(50 - ($higher + (100-$higher-$lower)/2));
  }
  
  private function markDivergingPairs($rows, $limit) {
    $exprows=explode("\n", trim($rows));
    $retrows=array();
    for ($i=0; $i<sizeof($exprows); $i++) {
      $cells = explode("&", $exprows[$i]);
      if (sizeof($cells)>1) {
        if ($this->calcmidpoint($cells[1], $cells[2]) > $limit) {
          if ($cells[1] < $cells[2]) {
            $cells[1] = $this->replace_add_color($cells[1], "red");
            $cells[2] = $this->replace_add_color($cells[2], "blue");
          } else {
            $cells[1] = $this->replace_add_color($cells[1], "blue");
            $cells[2] = $this->replace_add_color($cells[2], "red");          
          }
        }
        if ($this->calcmidpoint($cells[3], $cells[4]) > $limit) {
          if ($cells[3] < $cells[4]) {
            $cells[3] = $this->replace_add_color($cells[3], "red");
            $cells[4] = $this->replace_add_color($cells[4], "blue");
          } else {
            $cells[3] = $this->replace_add_color($cells[3], "blue");
            $cells[4] = $this->replace_add_color($cells[4], "red");          
          }
        }
        if ($this->calcmidpoint($cells[5], $cells[6]) > $limit) {
          if ($cells[5] < $cells[6]) {
            $cells[5] = $this->replace_add_color($cells[5], "red");
            $cells[6] = $this->replace_add_color($cells[6], "blue");
          } else {
            $cells[5] = $this->replace_add_color($cells[5], "blue");
            $cells[6] = $this->replace_add_color($cells[6], "red");          
          }
        }
      }
      $retrows[$i]= implode("&", $cells);
    }    
    return("\n".implode("\n",$retrows));
  }
  
  private function add_color($sortedarr) {
    $eliminateallbelow = 10;
    $coloredarr=array();
    foreach ($sortedarr as $row) {
      $cells = explode("&", $row);
      $key= $this->filter_key($cells[0]);
      $lastelement=sizeof($cells)-1;
      $noobs = explode("\\", $cells[$lastelement]);
      if (trim($noobs[0]) >= $eliminateallbelow ) {  // let only relevant rows pass
        if (in_array($key, $this->expectedpos)) {
          for ($i=1; $i<sizeof($cells)-1; $i+=2) {
            if (trim($cells[$i])>=0) $cells[$i]=$this->replace_add_color (trim($cells[$i]), "blue");
            if (trim($cells[$i])<0) $cells[$i]=$this->replace_add_color (trim($cells[$i]), "red");          
          }
        } elseif (in_array($key, $this->expectedneg)) {
          for ($i=1; $i<sizeof($cells)-1; $i+=2) {
            if (trim($cells[$i])<=0) $cells[$i]=$this->replace_add_color (trim($cells[$i]), "blue");
            if (trim($cells[$i])>0) $cells[$i]=$this->replace_add_color (trim($cells[$i]), "red");          
          }         
        } elseif (in_array($key, $this->expectednodir)) {
          for ($i=1; $i<sizeof($cells)-1; $i+=2) {
            $cells[$i]=$this->replace_add_color (trim($cells[$i]), "black");     
          }            
        } else {
          echo "ERROR: this key was not found: ".trim($cells[0])."\n";
        }
        $coloredarr[$key]= implode(" & ", $cells); 
      }
    }
    return ($coloredarr);
  }
  
  private function replace_add_color($string, $color) {
    return ("\\textcolor{".$color."}{".$string."}");
  }
  
  private function fontsize($rawstring, $fontsize) {
    return (str_replace("\begin{table}[ht]", "\begin{table}[ht]$fontsize", $rawstring));
  }
}
?>
